#============================================
# 聚合查询   aggregate
# 聚合查询通常情况下都是配合分组一起使用的
# 只要是跟数据库相关的模块
# 基本上都在django. db . models里面
# 如果上述没有那么应该在django . db里面
# from django 。db。models import Max, Min,SumyCount.Avg 
# 下面为单独使用，一般与分组一起用
# res =models. Book . objects . aggregate (Max(' price' ),Min( ' price ' ),Sum(' price'),Count('pk' ),Avg(' price'))
# print(res)
#============================================
# 分组查询  annotate
# 1.统计每一本书的作者个数
# author_ num是我们自己定义的字段用来存储统计出来的每本书对应的作者个数
# res = models.Book.objects.annotate(author__num=Count('authors__id')).values('title','author__num ')
# print(res)

# 2.统计每个出版社卖的最便宜的书的价格
# res = models . Publish. objects . annotate (min_price=Min( 'book__ price' )).vaLues(  name','min_price')

# 3. 统计不止一个作者的图书
# 1.先按服凰书分组求每一本书对应的作者个数
# 2.过滤出不止一个作者的书
# res = models.Book.objects.annotate(author_ num=Count('authors')).filter(autho num _gt=1).values('titLe',' author_num')
# 只要你的orm语句得出的结果还是个queryset对象
# 那么它就可以继续无限制的点queryset对象封装的方法
 
# 4.查询每个作者出的书的总价格
# res = models . Author . objects . annotate(sum_ .price=Sum(' book__ price ' )) .values('name'to ' sum_ price' )
# print(res)


# 如果我想按照指定的字段分组该如何处理呢?
# modeLs . Book . objects. values( ' price ' ) . annotate()
# 后续BBS作业会使用
#============================================
# F查询
# 1. 查询卖出数大于库存数的书籍
# F查询  能够帮助你直接获取到表中的某个字段对应的值
# from django. db . models import F
# res = models . Book. objects . filter(maichu__ gt=F(' kucun' ))
# print(res)

# 2.将所有书籍的价格提升500块
# models.Book.object.update (price=F( 'price') + 500)


# 共3将所有书的多称后頂加上爆款两个字
# 在操作字符类型的数据的时候F不能够直接做到字符串的拼接
# from django . db . models . functions import Concat
# from django . db . models import Value
# models . Book . objects . update(title=Concat(F('titLe ') VaLue('爆款' )))
#============================================
# Q查询
# 1.查询卖出数大于100或者价格小于600的书籍
# res = modeLs。Book . objects. filter(maichu__ gt=100 , price__ Lt=600)
# filter括号内多个参数是and关系
# from django.db.models import Q
# res = models . Book. objects . filter(Q(maichu__ gt=100) , Q(price_. Lt=600)) # Q包裹逗号分割还是and关系
# res = models . Book . objects . filter(Q (maichy__ gt=100) IQ(price_. Lt=600) # | or关系
# res = models . Book. objects . filter(~Q(mgpichu__ gt=100)JQ(price_. Lt=600)) # ~ not关系

# Q的高阶用法能够将 查询条件的左边也变成字符串的形式
# q=Q()
# q. connector = ' or'
# q. children. append(( 'maichu__gt',100))
# q. children. append((' price__Lt',600))
# res = models . Book. objects . filter(q)  #默认还是and关系
# print(res)
#============================================
# 开启事务
# from django. db import transaction
# with transaction. atomic():
# # sqL1
# # sqL2
# #在with代码快内书写的所有orm操作都是属于同一个事务
#============================================
# orm常用字段及其参数
# AutoField
# 主键字段pr imary_ key=True

# CharField

# varchar
# verbose_ name字段的注释
# max_ _length长度

# IntegerField 
# BigIntegerField

# DecimalField
# max_ digits=8
# decimal_ places=2

# EmailFiled
# varchar (254 )

# DateField   date
# DateTimeField   datetime
# auto_now :每次修改数据的时候都会自动更新当前时间
# auto_now_add :只在创建数据的时候记录创建时间后续不会自动修改了

# BooleanFiejd(Field)
# -布尔值类型
# 该字段传布尔值(False/True)
# 数据库里面存0/ 1

# TextField(Field)
# 文本类型
# 该字段可以用来存大段内容(文章、博客...)
# 没有字数限制

# FileField(Field )
# -字符类型
# upload_ to = " /data"
# 给该字段传一个文件对象，会自动将文件保存到/data目录下然后将文件路径保存到数据库中
# /data/a. txt
# 后面bbs作业也会涉及

#更多字段参考博客 


# # django除了给你提供了很多字段类型之外还支持你自定义字段
# class MyCharField (models . Field) :
    # def_ init__ ( self , max_ length, *args, **kwargs):
        # self .max_ length = max_ length
        # #调用父类的init方法
        # super( )._ _init__ (max_ length=max_ length, *args, **kwargs) #一 定要是关键字的形式传入
# def db_ type(self, connection) :
# 返回真正的数据类型及各种约束条件
# : param connection :
# : return:
#   return ' char(%s) '&self . max_ _length
# #自定义字段使用
# myfield = MyCharF ield(max_ 1ength=16,null=True)

#外键字段及参数
# unique= True
# ForeignKey (unique=True)   ===  OneToOneField( )
# #你在用前面字段创建一 对一orm会有一 个提示信息 orm推荐你使用后者但是 前者也能用
# db index
# 如果db_ index=True 则代表着为此字段设置索引
# (复习索引是什么)

# to_ field
# 设置要关联的表的字段默认不写关联的就是 另外- -张的主键字段

# on_ delete 
# 当删除关联表中的数据时，当前表与其关联的行的行为。
# django2. x及以上版本需要你自己指定外键字段的级联更新级联删除
#============================================
# 查询优化
#你给我实现获取到的是个数据对象 然后点titLe就能够拿到书名并且没有其他字段
# res = models.Book.objects.onLy('titLe')
#res=
# models.Book.objects.aLl()
# print(res) # <QuerySet [ <Book:三国演义爆款>，<Book: 红楼梦爆款>]
# for i in res:
# print(i. titLe) #点击onLy括号内的字段不会走数据库
# print(i.price) # 点击onLy括号内没有的字段会重新走数据库查询而all不需要走了

# res = modeLs . Book . objects. defer('titLe') # 对象除了没有titLe属性之外其他的都有
# for i in res:
# print(i. price)
# defer与onLy刚好相反
# defer括号内放的字段在括号内，查询出来的对象里面查询该字段需要重新走数据
# 而如果查询的是非括号内的字段则不需要走数据库了

# res = modeLs . Book . objects . seLect_ related( 'authors') # INNER JOIN联表
# seLect_ related内部直接先将book与publish连起来然后一次性将大表里面的所有数据
# 全部封装给查询出来的对象
# 这个时候对象无论是点击book表的数据还是pubLi sh的数据都无需再走数据库查询了
# select_ reLated括号内只能放外键字段
# 一对多一对一
# 多对多也不行
# for i in res:
# print(i. publish. name) # 每循环一次就要走-次数据库查询

# res = modeLs . Book . objects . prefetch_ reLated(' publish') #子查询
# prefetch_ related该方法内部其实就是子查询
# 将子查询查询出来的所有结果也给你封装到对象中
# 给你的感觉好像也是一次性搞定的
# for i in res:
# print (i. publish. name )
#============================================
# choice参数
# gender_ choices = (
# (1.'男')，
# (2 '女)，
# (3,'其他')，
# )
# gender = models. IntegerField(choices=gender_choices)
# score_ choices = (

# ('A', '优秀')，
# ('B','良好')，
# ('C', 及格')，
# ('D', '不合格')，
# #保证字段类型跟列举出来的元祖第个数据类型 一致即可
# score = models. CharField(choices=score_choices,nuLl=True)
# 该gender字段存的还是数字但是如果存的数字在上面元祖列举的范围之内
# 那么可以非常轻松的获取到数字对应的真正的内容

#取
# user_ obj = models. User .objects. filter(pk=1) . first( )
# print(user_ obj . gender )
#只要是choices参数的字段如果你想要获取对应信息固定写法get_字段名_display( )
# print(user_ obj.get_ gender_ display())
# user_ obj = models.User .objects. filter(pk=4) .first( )
#如果没有对应关系那么字段是什么还是展示什么
# print (user_obj.get_gender_display()) # 4
#============================================
# # MTV与MVC模型
# # MTV:Django号称是MTV模型
# M: models
# T: templates
# V: views
# # MVC:其实django本质也是MVC
# M: models
# V: views
# C: control ler
# # vue框架:MVVM模型
#============================================
# #全自动:利用orm自动帮我们创建第三张关系表
# class Book (models . Model) :
# name = models . CharField (max_ length=32)
# authors = models .ManyToManyF ield(to= ' Author ' )
# class Author ( models . Model) :
# name = models . CharField (max_ length=32 )
# 优点:代码不需要你写非常的方便还支持orm提供操作第三张关系表的方法...
# 不足之处:第三张关系表的扩展性极差(没有办法额外添加字段...)

# #纯手动
# class Book (models . Model) :
# name = models . CharField (max_ length=32)
# class Author (models . Model) :
# name = models . CharField (max_ length=32 )
# class Book2Author ( models . Model) :
# book_ id = models . Fore ignKey(to= ' Book' )
# author_ id = models . ForeignKey(to= ' Author')
# 优点:第三张表完全取决于你自己进行额外的扩展
# 不足之处:需要写的代码较多，不能够再使用orm提供的简单的方法
# 不建议你用该方式

#半自动
class Book (models . Model) :
    name = models . CharField (max_ length=32)
    authors = models .ManyToManyField( to= ' Author'，through= ' Book2Author'，through_fields=(' book', ' author')

class Author (models . Model ) :
    name = models . CharField (max_ length=32)
# books = models .ManyToManyField(to= ' Book',through= ' Book2Author '，through_ fields=( ' author',。book' ) 

)   
class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')
    
# through_ fields字段先后顺序   
# 判断的本质: 
# 通过第三张表查询对应的表需要用到哪个字段就把哪个字段放前面
# 你也可以简化判断
# 当前表是谁就把对应的关联字段放前面
# 半自动:可以使用orm的正反向查询但是没法使用add, set, remove , clear这四个方法




